home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Graphics 2D / IconDimming / IconDimming.c next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  11.9 KB  |  407 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        IconDimming.c
  3.  
  4.     Contains:    In System 7, selected non-open files are shown as            
  5.                 dimmed icons on the desktop.  This snippet shows            
  6.                 two different ways to achieve the same results in            
  7.                 an application.                                                
  8.                                                                                     
  9.                 The first method uses a custom color search                    
  10.                 procedure in place of the current device's to                
  11.                 create the dimming effect.  Once the image has                
  12.                 been copied to the destination, the custom                    
  13.                 search proc is then removed.                                
  14.                                                                                 
  15.                 In the second method the RGB components of the                
  16.                 icon's colortable entries are all dimmed before                
  17.                 the image is copied into the destination.  The                
  18.                 dimming algorithm used in this method simply            
  19.                 darkens each RGB component in half then takes                
  20.                 the two smaller components and darkens them                    
  21.                 in half again.  In System 7, this is similar                
  22.                 to what the Finder does.
  23.  
  24.     Written by: Edgar Lee    
  25.  
  26.     Copyright:    Copyright © 1992-1999 by Apple Computer, Inc., All Rights Reserved.
  27.  
  28.                 You may incorporate this Apple sample source code into your program(s) without
  29.                 restriction. This Apple sample source code has been provided "AS IS" and the
  30.                 responsibility for its operation is yours. You are not permitted to redistribute
  31.                 this Apple sample source code as "Apple sample source code" after having made
  32.                 changes. If you're going to re-distribute the source, we require that you make
  33.                 it clear in the source that the code was descended from Apple sample source
  34.                 code, but that you've made changes.
  35.  
  36.     Change History (most recent first):
  37.                 7/9/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  38.                 
  39.  
  40. */
  41. #include<MacTypes.h>
  42. #include<Quickdraw.h>
  43. #include<Windows.h>
  44. #include<Dialogs.h>
  45. #include<TextEdit.h>
  46. #include<Fonts.h>
  47. #include<Menus.h>
  48. #include<Events.h>
  49. #include<Resources.h>
  50.  
  51. /* Constant Declarations */
  52.  
  53. #define    WWIDTH        480
  54. #define    WHEIGHT        180
  55.  
  56. #define WLEFT        (((qd.screenBits.bounds.right - qd.screenBits.bounds.left) - WWIDTH) / 2)
  57. #define WTOP        (((qd.screenBits.bounds.bottom - qd.screenBits.bounds.top) - WHEIGHT) / 2)
  58.  
  59. typedef    struct
  60. {
  61.     PixMap    pixmap;        /* Pixmap used to store the icl8 pixel image. */
  62.     BitMap    mask;        /* Bitmap used to store the 1 bit mask image of the icl8. */
  63. }
  64. MyIconType;
  65.  
  66. /* Global Variable Definitions */
  67.  
  68. WindowPtr    gWindow;
  69.  
  70. void initMac();
  71. void createWindow();
  72. void loadIconResource();
  73. void doEventLoop();
  74.  
  75. void drawIconUnchanged();
  76. void drawIconUsingSearchProc();
  77. void drawIconUsingCTable();
  78.  
  79. void DimColor( RGBColor *aColor );
  80. long CompareComponents( unsigned short component0, unsigned short component1 );
  81.  
  82. static pascal Boolean SearchProc();
  83.  
  84. void main()
  85. {
  86.     MyIconType    icon;
  87.     
  88.     initMac();
  89.     
  90.     createWindow();
  91.     loadIconResource( &icon );
  92.  
  93.     doEventLoop( &icon );
  94. }
  95.  
  96. void initMac()
  97. {
  98.     MaxApplZone();
  99.     
  100.     InitGraf( &qd.thePort );
  101.     InitFonts();
  102.     InitWindows();
  103.     InitMenus();
  104.     TEInit();
  105.     InitDialogs( nil );
  106.     InitCursor();
  107.     FlushEvents( 0, everyEvent );
  108. }
  109.  
  110. void createWindow()
  111. {
  112.     Rect rect;
  113.     
  114.     SetRect( &rect, WLEFT, WTOP, WLEFT + WWIDTH, WTOP + WHEIGHT );
  115.     
  116.     gWindow = NewCWindow( 0L, &rect, "\pIconDimming", true, noGrowDocProc,
  117.                             (WindowPtr)-1L, true, 0L );
  118.     SetPort( gWindow );
  119.     
  120.     TextFont( kFontIDGeneva );
  121.     TextSize( 9 );
  122. }
  123.  
  124. void loadIconResource( icon )
  125. MyIconType    *icon;
  126. {
  127.     Handle        icnHandle;        /* Handle to the icon bitmap used for the mask. */
  128.     Handle        iclHandle;        /* Handle to the icl8 resource. */
  129.     char        depth;            /* Depth of the icl8 image. */
  130.     Rect        rect;            /* Bounding rect for the image. */
  131.     
  132.     SetRect( &rect, 0, 0, 32, 32 );
  133.     depth = 8;
  134.     
  135.     /* Create the mask. */
  136.     
  137.     icnHandle = GetResource( 'ICN#', 129 );
  138.     
  139.     HLock( icnHandle );
  140.     HNoPurge( icnHandle );
  141.     
  142.     (*icon).mask.baseAddr = *icnHandle + (4 * 32);
  143.     (*icon).mask.rowBytes = 4;
  144.     (*icon).mask.bounds = rect;
  145.     
  146.     /* Create a pixmap for the icl8 pixel image. */
  147.     
  148.     iclHandle = GetResource( 'icl8', 129 );
  149.     
  150.     HLock( iclHandle );
  151.     HNoPurge( iclHandle );
  152.     
  153.     (*icon).pixmap.baseAddr = *iclHandle;
  154.     (*icon).pixmap.rowBytes = ((32 * depth) / 8) | 0x8000;
  155.     (*icon).pixmap.bounds = rect;
  156.     (*icon).pixmap.pmVersion = 0;
  157.     (*icon).pixmap.packType = 0;
  158.     (*icon).pixmap.packSize = 0;
  159.     (*icon).pixmap.hRes = 72;
  160.     (*icon).pixmap.vRes = 72;
  161.     (*icon).pixmap.pixelSize = depth;
  162.     (*icon).pixmap.planeBytes = 0;
  163.     (*icon).pixmap.pmReserved = 0;
  164.     (*icon).pixmap.pixelType = 0;
  165.     (*icon).pixmap.cmpCount = 1;
  166.     (*icon).pixmap.cmpSize = depth;
  167.     (*icon).pixmap.pmTable = GetCTable( depth );
  168.     
  169.     /* Give a unique seed for the pixmap's colortable.  Note that this is        */
  170.     /*    necessary for two reasons.  (1) The pixmap's colortable is ignored by    */
  171.     /*    copybits or copymask if the source ctable's ctseed value matches that    */
  172.     /*    of the    destination's.  (2) Matching ctseed values prevent any custom    */
  173.     /*    searchProcs from being called.                                            */
  174.     
  175.     (**(*icon).pixmap.pmTable).ctSeed = GetCTSeed();
  176. }
  177.  
  178. void drawIconUnchanged( icon )
  179. MyIconType    *icon;
  180. {
  181.     Str255        title = "\pOriginal 'icl8'";
  182.     Rect        rect;
  183.  
  184.     /* Draw the original icl8 image unchanged. */
  185.     
  186.     SetRect( &rect, 0, 0, 160, 160 );
  187.     CopyMask( (BitMap *)&(*icon).pixmap, &(*icon).mask, &gWindow->portBits,
  188.                 &(*icon).pixmap.bounds, &(*icon).mask.bounds, &rect );
  189.                 
  190.     MoveTo( (rect.right - rect.left - StringWidth( title )) / 2 + rect.left,
  191.             rect.bottom + 15 );
  192.     DrawString( title );
  193. }
  194.  
  195. void drawIconUsingSearchProc( icon )
  196. MyIconType    *icon;
  197. {
  198.     Str255        title = "\p'icl8' using SearchProc Dimming";
  199.     Rect        rect;
  200.     GWorldPtr    gworld;            /* Offscreen used for the custom search procedure. */
  201.     CGrafPtr    currentPort;    /* Saved CGrafPort for later restore. */
  202.     GDHandle    currentDevice;    /* Saved gdDevice for later restore. */
  203.     
  204.     GetGWorld( ¤tPort, ¤tDevice );
  205.     
  206.     /* Install the custom search proc to an offscreen pixmap instead of the    */
  207.     /*    screen's in order to be courteous to other apps.                    */
  208.         
  209.     NewGWorld( &gworld, 8, &(*icon).pixmap.bounds, GetCTable( 8 ), nil, 0 );
  210.     HLock( (Handle)(*gworld).portPixMap );
  211.         
  212.     SetGWorld( gworld, nil );
  213.     AddSearch( NewColorSearchProc(SearchProc) );
  214.  
  215.     CopyBits( (BitMapPtr)&(*icon).pixmap, (BitMapPtr)&(*gworld).portPixMap, &(*icon).pixmap.bounds,
  216.                 &(**(*gworld).portPixMap).bounds, srcCopy, nil );
  217.     
  218.     DelSearch( NewColorSearchProc(SearchProc) );
  219.     SetGWorld( currentPort, currentDevice );
  220.     
  221.     /* Now copy the dimmed pixmap image to the window. */
  222.     
  223.     rect.left = (*icon).pixmap.bounds.right * 5;
  224.     rect.top = (*icon).pixmap.bounds.top;
  225.     rect.right = (*icon).pixmap.bounds.right * 5 + rect.left;
  226.     rect.bottom = (*icon).pixmap.bounds.bottom * 5;
  227.  
  228.     CopyMask( (BitMapPtr)(*(*gworld).portPixMap), &(*icon).mask, &gWindow->portBits,
  229.                 &(**(*gworld).portPixMap).bounds, &(*icon).mask.bounds, &rect );
  230.     
  231.     DisposeGWorld( gworld );
  232.     
  233.     MoveTo( (rect.right - rect.left - StringWidth( title )) / 2 + rect.left,
  234.             rect.bottom + 15 );
  235.     DrawString( title );
  236. }
  237.  
  238. static pascal Boolean SearchProc( color, position )
  239. RGBColor    *color;
  240. long        *position;
  241. {
  242.     #pragma unused(position)
  243.     /* Darken the RGB components in half.  Note that this routine could just    */
  244.     /*    have easily called DimColor; however, I wanted to show the difference    */
  245.     /*    between just dimming the components in half to what System 7 does.         */
  246.         
  247.     color->red >>= 1;
  248.     color->green >>= 1;
  249.     color->blue >>= 1;
  250.     
  251.     return false;
  252. }
  253.  
  254. void drawIconUsingCTable( icon )
  255. MyIconType    *icon;
  256. {
  257.     Str255        title = "\p'icl8' using Colortable Dimming";
  258.     Rect        rect;
  259.     short        index;            /* Index into the dimmed colortable */
  260.     CTabHandle    dimmedClut;     /* Holds dimmed version of icon’s colortable */
  261.     CTabHandle    savedClut;        /* Saves the icon’s original colortable */
  262.     
  263.     /* Save the icon’s color table and make a copy of it */
  264.     dimmedClut = savedClut = (*icon).pixmap.pmTable;
  265.     HandToHand( &(Handle)dimmedClut );
  266.  
  267.     /* Dim each of the colors in the copy of the color table */
  268.     for (index = 0; index <= (**dimmedClut).ctSize; ++index)
  269.         DimColor( &(**dimmedClut).ctTable[index].rgb );
  270.  
  271.     /* Install the dimmed copy of the color table */
  272.     (*icon).pixmap.pmTable = dimmedClut;
  273.     
  274.     rect.left = (*icon).pixmap.bounds.right * 10;
  275.     rect.top = (*icon).pixmap.bounds.top;
  276.     rect.right = (*icon).pixmap.bounds.right * 5 + rect.left;
  277.     rect.bottom = (*icon).pixmap.bounds.bottom * 5;
  278.     
  279.     /* Now copy the dimmed pixmap image to the window. */
  280.     
  281.     CopyMask( (BitMap *)&(*icon).pixmap, &(*icon).mask, &gWindow->portBits,
  282.                 &(*icon).pixmap.bounds, &(*icon).mask.bounds, &rect );
  283.     
  284.     (*icon).pixmap.pmTable = savedClut;
  285.     DisposeCTable( dimmedClut );
  286.  
  287.     MoveTo( (rect.right - rect.left - StringWidth( title )) / 2 + rect.left,
  288.             rect.bottom + 15 );
  289.     DrawString( title );
  290. }
  291.  
  292. /******************************************************************************\
  293. * DimColor - Dim one color for selection
  294. *        written by Forrest Tanaka
  295. * This routine dims the color that’s passed in the aColor parameter so that
  296. * it’s suitable to use for making an icon look selected.  It works by dimming
  297. * all components by half, and then dimming the smaller two components by half
  298. * again.  By keeping the largest component dimmed by only half, we keep the
  299. * saturation of the color approximately what it was before it was dimmed.
  300. \******************************************************************************/
  301.  
  302. void DimColor( 
  303.     RGBColor *aColor)
  304. {
  305.     unsigned short *biggest; /* Pointer to the biggest component */
  306.  
  307.     /* Dim all components by half */
  308.     aColor->red >>= 1;
  309.     aColor->green >>= 1;
  310.     aColor->blue >>= 1;
  311.  
  312.     /* If aColor isn’t nearly gray, dim smallest 2 components again by half */
  313.     if (CompareComponents( aColor->red, aColor->green ) != 0 ||
  314.             CompareComponents( aColor->red, aColor->blue ) != 0)
  315.     {
  316.         /* Point to the larger of red and green */
  317.         if (CompareComponents( aColor->red, aColor->green ) > 0)
  318.             biggest = &aColor->red;
  319.         else
  320.             biggest = &aColor->green;
  321.  
  322.         /* Point to the larger of previous test and blue */
  323.         if (CompareComponents( aColor->blue, *biggest ) > 0)
  324.             biggest = &aColor->blue;
  325.  
  326.         /* Dim smaller two components by half */
  327.         if (&aColor->red != biggest)
  328.             aColor->red >>= 1;
  329.         if (&aColor->green != biggest)
  330.             aColor->green >>= 1;
  331.         if (&aColor->blue != biggest)
  332.             aColor->blue >>= 1;
  333.     }
  334. }
  335.  
  336. /******************************************************************************\
  337. * CompareComponents - Compare two components for difference and equality
  338. *        written by Forrest Tanaka
  339. * This routine compares two components of an RGBColor that are passed in the
  340. * component0 and component1 parameters.  If they’re within 512 units of each
  341. * other, then zero is returned.  Otherwise, the positive difference is returned
  342. * if component0 is greater than component1, or the negative of the difference
  343. * is returned if component1 is greater than component0.
  344. \******************************************************************************/
  345.  
  346. long CompareComponents(
  347.     unsigned short component0, /* First component to check */
  348.     unsigned short component1) /* Second component to check */
  349. {
  350.     long difference; /* Difference between components */
  351.  
  352.     /* Calculate the difference between the components */
  353.     difference = (unsigned long)component0 - (unsigned long)component1;
  354.  
  355.     /* If the difference is within 512 units, then consider the components the same */
  356.     if ((difference < 512) && (difference > -512))
  357.         return 0;
  358.     else
  359.         return difference;
  360. }
  361.  
  362. void doEventLoop( icon )
  363. MyIconType    *icon;
  364. {
  365.     EventRecord event;
  366.     WindowPtr   window;
  367.     short       clickArea;
  368.     Rect        screenRect;
  369.  
  370.     for (;;)
  371.     {
  372.         if (WaitNextEvent( everyEvent, &event, 0, nil ))
  373.         {
  374.             if (event.what == mouseDown)
  375.             {
  376.                 clickArea = FindWindow( event.where, &window );
  377.                 
  378.                 if (clickArea == inDrag)
  379.                 {
  380.                     screenRect = (**GetGrayRgn()).rgnBBox;
  381.                     DragWindow( window, event.where, &screenRect );
  382.                 }
  383.                 else if (clickArea == inContent)
  384.                 {
  385.                     if (window != FrontWindow())
  386.                         SelectWindow( window );
  387.                 }
  388.                 else if (clickArea == inGoAway)
  389.                     if (TrackGoAway( window, event.where ))
  390.                         return;
  391.             }
  392.             else if (event.what == updateEvt)
  393.             {
  394.                 window = (WindowPtr)event.message;    
  395.                 SetPort( window );
  396.                 
  397.                 BeginUpdate( window );
  398.                 
  399.                 drawIconUnchanged( icon );
  400.                 drawIconUsingSearchProc( icon );
  401.                 drawIconUsingCTable( icon );
  402.                 
  403.                 EndUpdate( window );
  404.             }
  405.         }
  406.     }
  407. }